<?php
//-------------------------------------------------------------------------------------------------------
    require_once($config['app_dir'] . '/includes/db.class.php');
    require_once($config['app_dir'] . '/includes/mailer.class.php');
    require_once($config['app_dir'] . '/includes/template.class.php');
    require_once($config['app_dir'] . '/includes/date.class.php');

    require_once($config['app_dir'] . '/classes/stockplot.view.php');
    require_once($config['app_dir'] . '/classes/stockplot.data.php');
    require_once($config['app_dir'] . '/classes/stockmailer.data.php');

    require_once($config['app_dir'] . '/classes/log.class.php');
    require_once($config['app_dir'] . '/classes/user.data.php');
    require_once($config['app_dir'] . '/classes/ActiveRecords.class.php');
    require_once($config['app_dir'] . '/classes/DataLists.class.php');
    //---------------------------------------------------------------------------------------------------
    class objHash {

        static public function Hash($aValue) {
            return crypt($aValue, CRYPT_BLOWFISH);
        }//Hash

    } //class Hash
    //----------------------------------------------------------------------------------------------------
    abstract class objStockMailer {
            public $temp_dir='';
            public $loging = true;
            public $width = 500;
            public $height = 315;
            public $forecast_id = false;

            protected $_image_filename = '';
            protected $_image = '';
            protected $_news_text=false;
            protected $Log = false;
            protected $send_order = array(5, 3, 2, 4, 1); // 5 - direct SMS message type

        public function __construct() {
          global $config;
           $this->temp_dir = $config['tmp_dir'];
           $this->SMSenabled();
        } //constructor

        // don't send SMS if it's disabled in root config
        public function SMSenabled() {
          global $config;

          if (!$config['sms']['enabled']) {
          	$this->send_order = array(3, 2, 4, 1);
          	return false;
          } else return true;
        } //SMSenabled

        abstract protected function StartLog(); //StartLog

        protected function ClearImage($messagetype=1) {
            if( $this->_image && (1==$messagetype || 2==$messagetype) )   unlink($this->_image);
        } //ClearMessage

        protected function Forecast(objStockModel $StockModel) {
            return ($this->forecast_id ? $StockModel->GetForecastByID($this->forecast_id) : $StockModel->GetLastForecast() );
        }//Forecast

        public function GenerateIDbyParam($aPair, $aBeginPrice='', $aBeginTime='', $aEndPrice='', $aEndTime='', $aSystem=false, $messagetype=false) {
            return md5('mailer_'.$aPair . ' ' .$aBeginPrice . ' ' . $aBeginTime.' '.$aEndPrice. ' ' . $aEndTime . ' '. $aSystem.' '.strval($messagetype));
        } //GenerateID

        public function GenerateID(objStockModel $StockModel, $messagetype=false) {
            return $this->GenerateIDbyParam($StockModel->GetPair(),
                                            $StockModel->GetBeginPrice(),  $StockModel->GetBeginTime(),
                                            $StockModel->GetEndPrice(), $StockModel->GetEndTime(),
                                            $StockModel->GetSystem(),
                                            $messagetype);
        } //GenerateID

        public function GetCacheMailID(objStockModel $StockModel, $prefix='cachemail__') {
            $pmail_id = 'when_' . $StockModel->GetPair() . '_child_' . $StockModel->GetStart() . '_was_' . $StockModel->GetFinish() . '_a_child.' . $StockModel->GetSystem();

            return 'pmail__' . objHash::Hash($pmail_id). '.gif' ;
        }//GetCacheMailID

        protected function GetSubject($aLang, objStockModel $StockModel, $flagCaching=false, $aID=false, $mode=false) {

            $id = $aID;
            $TemplateSource='EmailSubject.tpl';

            $Subject = new objTemplate($aLang);
            if( $flagCaching ) {
                if( !$id ) $id = $this->GenerateID($StockModel);
                //--------------------------------------------------------------
                $Subject->caching = 2;
                $Subject->cache_lifetime = -1;
                //--------------------------------------------------------------
                if( $Subject->is_cached($TemplateSource, $id) ) {
                    return $Subject->Fetch($TemplateSource, $id);
                }//if cached
            }//if cahcing enable

            $Subject->Assign('forecast', $this->Forecast($StockModel)/*$StockModel->GetLastForecast()*/);
            $Subject->Assign('mode', $mode);

            return $Subject->Fetch($TemplateSource, $id);
        } //getSubject

        protected function GetBody($aLang, objStockModel $StockModel, $messagetype, $flagCaching=false, $aID=false, $trade_mode=false) {
          global $config;
            $id = $aID;
            $body = false;
            $header = false;
            $main = false;
            $footer = false;

            $templateBody = '_ForecastItem.tpl';
            $templateHeader = '_ForecastItemHeader.tpl';
            $templateMain = '_ForecastItemBody.tpl';
            $templateFooter = '_ForecastItemFooter.tpl';

            $Body = new objTemplate($aLang);
            $Header = new objTemplate($aLang);
            $Main = new objTemplate($aLang);
            $Footer = new objTemplate($aLang);

            if( $flagCaching ) {
                if( !$id ) $id = $this->GenerateID($StockModel, $messagetype);
                //--------------------------------------------------------------
                $Body->caching = 2;
                $Body->cache_lifetime = -1;

                $Header->caching = 2;
                $Header->cache_lifetime = -1;

                $Main->caching = 2;
                $Main->cache_lifetime = -1;

                $Footer->caching = 2;
                $Footer->cache_lifetime = -1;
                //--------------------------------------------------------------
                if( $Body->is_cached($templateBody, $id) ) {
                    $body = $Body->Fetch($templateBody, $id);
                }//if cached

                if( false===$body && $Header->is_cached($templateHeader, $id) ) {
                    $header = $Header->Fetch($templateHeader, $id);
                }//if cached

                if( false===$body &&  $Main->is_cached($templateMain, $id) ) {
                    $main = $Main->Fetch($templateMain, $id);
                }//if cached

                if(  false===$body && $Footer->is_cached($templateFooter, $id) ) {
                    $footer = $Footer->Fetch($templateFooter, $id);
                }//if cached
            }//if cahcing enable

            if(  false===$body && false===$header ) {
                $Header->Assign('forecast', $this->Forecast($StockModel)/*$StockModel->GetLastForecast()*/);
                $Header->Assign('image', $this->_image_filename);
                $Header->Assign('flagShowSystem', 1);
                $Header->Assign('news', $this->_news_text);
                $Header->Assign('CacheMailID', $this->GetCacheMailID($StockModel) );
                $Header->Assign('AplicationRoot', $config['host']['root']);
                $Header->Assign('messagetype', $messagetype);
                $Header->Assign('trade_mode', $trade_mode);
                $header = $Header->Fetch($templateHeader, $id);
            } //if header is empty

            if(  false===$body && false===$main ) {
                $Main->Assign('forecast', $this->Forecast($StockModel) /*$StockModel->GetLastForecast()*/);
                $Main->Assign('image', $this->_image_filename);
                $Main->Assign('news', $this->_news_text);
                $Main->Assign('CacheMailID', $this->GetCacheMailID($StockModel) );
                $Main->Assign('AplicationRoot', $config['host']['root']);
                $Main->Assign('messagetype', $messagetype);
                $main = $Main->Fetch($templateMain, $id);
            } //if main is empty

            if(  false===$body && false===$footer ) {
                $Disclaimer = new objTemplate($aLang);

                $Footer->Assign('messagetype', $messagetype);
                $Footer->Assign('disclaimer', $Disclaimer->Fetch('_Disclaimer.tpl')); //XXX multilanguage disclaimer
                $footer = $Footer->Fetch($templateFooter, $id);
            } //if footer is empty

            if(  false===$body ) {
                $Body->Assign('header', $header);
                $Body->Assign('body', $main);
                $Body->Assign('footer', $footer);
                $body = $Body->Fetch($templateBody, $id);
            }//if is body is empty

            return $body;
        } //getBody


        protected function GetSMSBody($StockModel, $phone, $mode) {
        	global $config;

            $SMSBodyTemplate = new objTemplate();
			$SMSBodyTemplate->Assign('user', $config['sms']['user']);
			$SMSBodyTemplate->Assign('pass', $config['sms']['pass']);
			$SMSBodyTemplate->Assign('api_id', $config['sms']['api_id']);
            $SMSBodyTemplate->Assign('forecast', $this->Forecast($StockModel)/*$StockModel->GetLastForecast()*/);
            $SMSBodyTemplate->Assign('phone',$phone);
            $SMSBodyTemplate->Assign('trade_mode',$mode);
            $SMSBody = $SMSBodyTemplate->Fetch('SMSDirectBody.tpl');

            return $SMSBody;
        } //getSMSBody

        public function ClearCache($aLangArr, objStockModel $StockModel, $aID=false){
            $id = $aID;

            foreach($aLangArr as $aLang) {
                $Template = new objTemplate($aLang['sys_name']);

                foreach($this->send_order as $messagetype) {
                    if( !$id ) $id = $this->GenerateID($StockModel, $messagetype);
                    $Template->clear_cache('_ForecastItemHeader.tpl', $id);
                    $Template->clear_cache('_ForecastItemBody.tpl', $id);
                    $Template->clear_cache('_ForecastItemFooter.tpl', $id);
                    $Template->clear_cache('_ForecastItem.tpl', $id);

                    if( !$id ) $id = $this->GenerateID($StockModel);
                    $Template->clear_cache('EmailSubject.tpl', $id);
                }//foreach messagetype
            }//foreach language

            return true;
        } //ClearCache

        protected function GenerateImageFilename($image_type, $id=false,$aPair=false) {
          global $config;
            $pair = $aPair;
            if( $pair ) $pair = str_replace('/', '', $pair);

            $this->_image_filename = $pair . ($pair ? '_' : '') . 'Forecast' . ($id ? '__' : '') . $id;
            $this->_image = $config['jpgraph']['cache_dir'] . $this->_image_filename. '.' . $image_type;
            $this->_image_filename =  $pair . '_Forecast' . '.' . $image_type;
        } //GenerateImageFilename

        protected function GetImage(objStockModel $StockModel, $aPair=false, $flagCaching=false, $aID=false) {
          global $config;
            $id = $aID;
            if( !($pair=$StockModel->GetPair()) ) $pair = $aPair;
            try {
                $StockView = new objStockView($this->width, $this->height);
                $data = false;
                if( !$id ) $data = $StockModel->getData();
                if( $flagCaching && !$id ) $id = $this->GenerateID($StockModel);

                $this->GenerateImageFilename($StockView->type, $id, $pair);

                if( !($flagCaching && file_exists($this->_image)) ) {
                    $StockView->HideNews();//!!!!!!!!!

                    if( !$data ) $data = $StockModel->getData();
                    $StockView->SetData($data);

                    //$this->_news_text = $StockView->RenderNews();
                    $StockView->Render($this->_image);
                } //file not rendering yet
            } catch (Exception $e) {
                echo 'Error: ',  $e->getMessage(), "\n";
            }
            return $this->_image;
    	} //getImage

        public function GetUnsubscribeBlock($aLang, $url, $email) {
            $Block = new objTemplate($aLang);
            $Block->Assign('url', $url);
            $Block->Assign('code', md5('unsubscribe' .$email . 'the knowledge is the power.'));
            return $Block->Fetch('_EmailUnsubscribe.tpl');
        } //GetUnsubscribeBlock


        abstract function Send();
    }//class StockMailer

    //---------------------------------------------------------------------------------------------------
    // StockParamMailer
    //---------------------------------------------------------------------------------------------------
    class objStockParamMailer extends objStockMailer {
            public $trade = false;
            public $start = false;
            public $finish = false;
            public $system = false;
            public $group_id = -1;
            public $trade_action = 0; //open
            public $mail_session_id = false;
            public $prefix = 'param-';
            public $show = false;

            protected $StockMailerModel = false;

        public function __construct($aTrade, $aStart, $aFinish, $aGroup=-1, $aSystem=false) {
            parent::__construct();
            $this->trade = intval($aTrade);
            $this->start = strval($aStart);
            $this->finish = strval($aFinish);
            $this->group_id = intval($aGroup);
            $this->system = intval($aSystem);
        } //constructor

        protected function StartLog() {
            //$this->Log  = new objTextLog('mailerparam');
        } //StartLog

        public function __destruct() {
            $this->ClearImage();
        } //destructor

        protected function SendAlert() {
          global $config;
            $AlertMailer = new objMailer();
            $AlertMailer->AddAddress($config['admin']['email']);
            $AlertMailer->isHTML( true );
            $AlertMailer->Subject = 'Error Alert: hang up forecast';
            $AlertMailer->Body = $this->trade . ' ' . $this->start . ' ' . $this->finish;
            return $AlertMailer->Send();
        } //SendAlert

        private function getEmails($messagetype) {
            if( 3==$messagetype)  $emails = $this->StockMailerModel->GetSMSEmailsArr($messagetype, $this->trade, $this->system);// XXX system
            else if( 5==$messagetype) {
                $emails = $this->StockMailerModel->GetSMSDirectArr($messagetype, $this->trade, $this->system);
            }
            else $emails = $this->StockMailerModel->getEmailsArr($messagetype, $this->trade, $this->system);//XXX system
            return $emails;
        } //getEmails

        public function Send() {
          global $config;
            if( $this->show ) echo "<pre>";
            if( $this->loging ) $this->StartLog();

            $StockValidator = new objStockValidationPeriod($this->trade, $this->start, $this->finish);
            if( !$StockValidator->isValid() ) {
                if( $this->show ) echo "ALERT";
                $this->SendAlert();
                return false;
            }
            //-------------------------------------------------------------------------------------------
            $this->StockMailerModel = new objStockMailerModel($this->group_id);
            //-------------------------------------------------------------------------------------------
            $Trade = new objDBTrade();
            $Trade->Load($this->trade);

            $StockModel = new objStockModel($this->trade, $this->start, $this->finish, false, $this->system);
            $StockModel->StrongInterval(false);
            $StockModel->SetNews(false);

            $image = $this->GetImage($StockModel, $Trade->pair);

            $StockID = $this->prefix . $this->GenerateID($StockModel);

            $MailerSession = new objDBMailer_Session();
            if( !$this->mail_session_id ) {
                $MailerSession->Start();
                $this->mail_session_id = $MailerSession->GetID();
                $SessionCount = 0;
                $flag_rebuild = false;
            } else {
                $MailerSession->Load($this->mail_session_id);
                $SessionCount = $MailerSession->countmails;

                $this->StockMailerModel->mailer_session_id = $this->mail_session_id;
                $flag_rebuild = true;
            }

            $MailerMail = new objDBMailer_Mail();
            $MailerStatus = new objDBMailer_Status();
            //-------------------------------------------------------------------------------------------
            for($mtype=0; $mtype<count($this->send_order); $mtype++) {
                $messagetype = $this->send_order[$mtype];
                $BodyID = $this->prefix . $this->GenerateID($StockModel, $messagetype);

                $emails = $this->getEmails($messagetype);
                if( $this->show ) echo "\n\n\n messagetype=$messagetype\n";
                if( empty($emails) ) continue;
                //-----------------------------------------------------------------------------------------------
                $tries_count = 0;
                while( !empty($emails) && $tries_count<=10 ) {
                    //-------------------------------------------------------------------------------------------
                    $tries_count++;
                    if( $this->show ) echo "\n\n tries=$tries_count\n";
                    foreach( $emails as $item ) {
                        if( $this->show ) echo $item['email']."\n";
                        //---------------------------------------------------------------------------------------
                        if( 3!=$messagetype && 5!=$messagetype) {
                            $subject = $this->GetSubject($item['language'], $StockModel, true, $StockID);
                        } else {
                            $subject = 'FORECAST';
                        }

                        if( 5!=$messagetype ) {
                            $body = $this->GetBody($item['language'], $StockModel, $messagetype, true, $BodyID, $this->trade_action) .
                                ((1==$messagetype || 4==$messagetype) ? '<br>' : "\n") .
                                $this->GetUnsubscribeBlock($item['language'], $config['host']['root'], $item['email']);
                        } else { // direct sms sending
                            $body = $this->GetSMSBody($StockModel, $item['email'],$this->trade_action);
                        }
                        //---------------------------------------------------------------------------------------
                        // save message
                        $MailerMail->mailid = NULL;
                        $MailerMail->forecastid = $StockModel->GetForecastID();
                        $MailerMail->userid = $item['id'];
                        $MailerMail->messageid = $StockID;
                        $MailerMail->messagetype = $messagetype;
                        $MailerMail->subject = $subject;
                        $MailerMail->body = $body;
                        $MailerMail->attachment = '';
                        $MailerMail->sessionid = $MailerSession->GetID();
                        $MailerMail->imagefilename = $this->_image_filename;
                        $MailerMail->tries = 1;
                        $MailerMail->ishtml = (1==$messagetype || 4==$messagetype);
                        $MailerMail->statusid = '9999';
                        $MailerMail->Insert();

                        $MailerStatus->mailstatusid = NULL;
                        $MailerStatus->mailid = $MailerMail->GetID();
                        $MailerStatus->statusid = '9999';
                        $MailerStatus->description = 'created. ready for send';
                        $MailerStatus->date = NULL;
                        $MailerStatus->Insert();

                        $MailerMail->BLOB_Update($MailerMail->GetID(), $image);
                        // / save message
                        //---------------------------------------------------------------------------------------
                        $SessionCount++;
                        //---------------------------------------------------------------------------------------
                    } //for each email
                    if( !$flag_rebuild ) break;
                    $emails = $this->getEmails($messagetype);
                    //-------------------------------------------------------------------------------------------
                }//while list not empty

            }//for all message types

            $this->ClearCache($this->StockMailerModel->getLanguages(), $StockModel, $StockID);//!!! 20071110

            $MailerSession->countmails = $SessionCount;
            $MailerSession->Save();
            if( $this->show ) echo "</pre>";
            return true;
        } //Send
    }// class StockParamMailer

    //---------------------------------------------------------------------------------------------------
    // StockDoneParamMailer
    //---------------------------------------------------------------------------------------------------
    class objStockDoneParamMailer extends objStockParamMailer{
        public $prefix = 'paramdone-';
    	public $trade_action = 1; //close

        protected function StartLog() {
            //$this->Log  = new objTextLog('mailerparamdone');
        } //StartLog

        public function GenerateIDbyParam($aPair, $aBeginPrice='', $aBeginTime='', $aEndPrice='', $aEndTime='', $aSystem=false, $messagetype=false) {
            return md5('mailerdone_'.$aPair . ' ' .$aBeginPrice . ' ' . $aBeginTime.' '.$aEndPrice. ' ' . $aEndTime . ' '. $aSystem.' '.strval($messagetype));
        } //GenerateID

        protected function GetSubject($aLang, objStockModel $StockModel, $flagCaching=false, $aID=false, $mode='close') {
            return parent::GetSubject($aLang, $StockModel, $flagCaching, $aID, $mode);
        } //GetSubject

        protected function GetImage(objStockModel $StockModel,  $aPair=false, $flagCaching=false, $aID=false) {
          global $config;

            $id = $aID;
            if( !($pair=$StockModel->GetPair()) ) $pair = $aPair;
            $StockView = new objStockView($this->width, $this->height);
            if( !$id ) $data = $StockModel->getData();
            //if( $this->show ) var_dump($data);
            //-------------------------------------------------------------------------------------------
            if( $flagCaching && !$id ) $id = $this->GenerateID($StockModel);
            $this->GenerateImageFilename($StockView->type, $id, $pair);

            if( !($flagCaching && file_exists($this->_image)) ) {
                $StockView->HideNews();//!!!!!!!!!

                if( !$data ) $data = $StockModel->getData();
                $StockView->SetData($data);

                $StockView->SetVectorColors(array('darkgreen', 'darkgreen', 'orange', 'red'));
                $StockView->setLegendTitles(array('darkgreen'=>'correct forecast', 'red'=>'incorrect forecast'));
                //$this->_news_text = $StockView->RenderNews();

                $StockView->Render($this->_image);
            } //file not render yet
            return $this->_image;

    	} //getImage
    } //class StockDoneParamMailer

    //--------------------------------------------------------------------------------------------------
    // StockUserMailer
    //---------------------------------------------------------------------------------------------------
    class objStockUserMailer  extends objStockMailer{
            protected $_trades = array();
            protected $UserRecord = false;
            protected $TradeRecord = false;
            protected $SystemRecord = false;

        public function __construct($user_id) {
            parent::__construct();
            $this->Log  = new objTextLog('maileruser');

            $UserModel = new objUserModel();
            $this->UserRecord = $UserModel->ActiveRecord();
            $this->UserRecord->Load("UserID=$user_id");

            if( !$this->UserRecord->login )
                throw new Exception("User ID=$user_id does not exist in database.");
            if( !$this->UserRecord->active )
                throw new Exception("User ID=$user_id ($this->UserRecord->login) is not active user.");

            $this->_trades = $UserModel->getTrades($user_id);

            $this->TradeRecord = new objDBTrade();
            $this->SystemRecord = new objDBSystem();
        } //constructor

        public function __destruct() {
        } //destructor

        protected function StartLog() {
            $this->Log  = new objTextLog('maileruser');
        } //StartLog

        function Send() {
          global $config;
            if( empty($this->_trades) )    return true;
            if( $this->loging ) $this->StartLog();
            //var_dump($this->_trades);
            foreach( $this->_trades as $item) {

                $ChartPeriod = new objChartPeriod();
                $ChartPeriod->flag_only_active = true;
                $period = $ChartPeriod->GetPeriod($item['SystemID'], $item['TradeID']);
                /*
                var_dump($item);
                var_dump($period);
                */
                if( !$period ) continue;
                $this->TradeRecord->Load($item['TradeID']);
                $period['trade'] = $item['TradeID'];
                $period['system'] = $item['SystemID'];
                $period['pair'] = $this->TradeRecord->pair;
                //-------------------------------------------------------------------------------------------
                $StockValidator = new objStockValidationPeriod($period['trade'], $period['start'], /*date('Y-m-d',$tmp_finish)*/ $period['finish'], $period['system']);
                if( !$StockValidator->isValid() ) {
                    $AlertMailer = new objMailer();
                    $AlertMailer->AddAddress($config['admin']['email']);
                    $AlertMailer->isHTML( true );
                    $AlertMailer->Subject = 'Error Alert: hang up forecast';
                    $AlertMailer->Body = $period['trade'].' '. $period['start'].' '. date('Y-m-d',$tmp_finish);
                    $AlertMailer->Send();
                    //continue; //XXX: senf hang up forecast to users
                }
                //-------------------------------------------------------------------------------------------
                $StockModel = new objStockModel($period['trade'], $period['startFormated'], $period['finishFormated'], false, $period['system']);//build model
                $StockModel->StrongInterval(false);
                $StockModel->SetNews(false);
                $image = $this->GetImage($StockModel, $period['pair'], $enableCache, $id);
                //-------------------------------------------------------------------------------------------
                if( !$StockModel->isNewForecast() ) {
                    continue;
                }
                //-------------------------------------------------------------------------------------------
                $enableCache = ((DateConvert::Date2('U') - $period['finish'] ) > 60*60*24 );
                $id = ($enableCache ? 'maileruser_'.$StockModel->GenID() : false);
                //-------------------------------------------------------------------------------------------
                $Mailer = new objMailer();
                $Mailer->isHTML( 1==$this->UserRecord->messagetype || 4==$this->UserRecord->messagetype );

                $Mailer->Subject = $this->GetSubject($this->UserRecord->language, $StockModel, $enableCache, $id);
                $Mailer->Body = $this->GetBody($this->UserRecord->language, $StockModel, $this->UserRecord->messagetype, $enableCache, $id);
                //-------------------------------------------------------------------------------------------
                $attach_filename = str_replace('/','',$period['pair']).'_Forecast.gif';
                switch( $this->UserRecord->messagetype ) {
                    case 1:
                        $Mailer->AddEmbeddedImage($image, $this->_image_filename, $this->_image_filename);
                    break;
                    //----------------------------------------------------------
                    case 2:
                        $Mailer->AddAttachment($image, $this->_image_filename);
                    break;
                    //----------------------------------------------------------
                    //----------------------------------------------------------
                    case 4:
                        @copy($image, $config['jpgraph']['cache_dir'] . $this->GetCacheMailID($StockModel));
                    break;
                }
                //-------------------------------------------------------------------------------------------
                $Mailer->AddAddress($this->UserRecord->login, $this->UserRecord->name);
                //-------------------------------------------------------------------------------------------
                $result = $Mailer->Send();
                if( $this->loging ) {
                    $log_data = $Mailer->Message;
                    $log_data['result'] = $Mailer->ErrorInfo;

                    $this->Log->Add( new objMailerLogRecord($log_data) );
                    $this->Log->Flush();
                    unset($log_data);
                }//loging
                //-------------------------------------------------------------------------------------------
                if( !$result ) {
                    throw new Exception("There was an error sending the message. Error: " . $Mailer->ErrorInfo);
                }
                //-------------------------------------------------------------------------------------------
                if( !$enableCache ) $this->ClearImage($this->UserRecord->messagetype);
                unset($period);
            }//foreach

            return true;
        } //Send

    } //class objStockUserMailer
    //---------------------------------------------------------------------------------------------------
    class objExportServiceClients {
            protected $_db = false;
            protected $_system = false;
            protected $_sql_querys = array();

        public function __construct($aSystem=false) {
            $this->_system = $aSystem;

            $this->_db = objDataBase::GetInstance();
            $this->_sqls();
        } //constructor

        public function GetList() {
            $data_emails = $this->_db->handler->getAll($this->_sql_querys['emails']);
            $emails = array(); $i = 0;
            foreach($data_emails as $item) {
                $emails[$i] = array(
                                  'email' => strval($item['Email']),
                                  'name' => strval($item['Name']),
                                  'template1' => strval($item['Template1']),
                                  'template2' => strval($item['Template2']),
                                  'template3' => strval($item['Template3']),
                                  'subject1' => strval($item['Subject1']),
                                  'subject2' => strval($item['Subject2']),
                                  'subject3' => strval($item['Subject3']),
                                  'system' => strval($item['SystemID']),
                                  );

                $emails[$i]['mailer']['host'] = strval($item['MailerHost']);
                $emails[$i]['mailer']['port'] = strval($item['MailerPort']);
                $emails[$i]['mailer']['username'] = strval($item['MailerUserName']);
                $emails[$i]['mailer']['password'] = strval($item['MailerPassword']);
                $emails[$i]['mailer']['email'] = strval($item['MailerEmail']);
                $emails[$i]['mailer']['emailfrom'] = strval($item['MailerEmailFrom']);
                $i++;
            }//foreach
            return $emails;
        } //GetList

        protected function _sqls() {
            $this->_sql_querys['emails'] =
            " SELECT  " .
              " s.Name, " .
              " s.Email, " .
              " s.Template1, " .
              " s.Template2, " .
              " s.Template3, " .
              " s.Subject1, " .
              " s.Subject2, " .
              " s.Subject3, " .
              " s.MailerHost, ".
              " s.MailerPort, ".
              " s.MailerUserName, ".
              " s.MailerPassword, ".
              " s.MailerEmail, ".
              " s.MailerEmailFrom, ".
              " ss.ServiceID, " .
              " ss.SystemID " .
            " FROM " .
              " fa_services_clients_systems ss " .
              " LEFT OUTER JOIN fa_service_clients s ON (ss.ServiceID = s.ID) " .
            " WHERE (1=1) " .
                    ($this->_system ? " AND (ss.SystemID=$this->_system) " : "");
        } //_sqls

    }//class ExportServiceClients
    //---------------------------------------------------------------------------------------------------
    class objForecatsBeginTimeShow extends objObject implements iErrorHandler{
            public $data = false;
            public $flag_simple = false;

            protected $_db = false;
            protected $_sql_querys = false;
            protected $_trade = false;
            protected $_system = false;
            protected $_date = false;
            protected $_error_str = array('no error',//0
                                          'Input parameters are empty'//1
                                         );

        public function __construct($aTrade, $aDate, $aSystem=false) {
            $this->_trade = $aTrade;
            $this->_date = intval($aDate);
            $this->_system = intval($aSystem);

            if( !$this->_trade || !$this->_date ) {
               $this->Dump();
               throw new Exception($this->Error(1));
            }
            $this->_db = objDataBase::GetInstance();
            $this->_sqls();
        } //constructor

        public function ClassName() {
            return  __CLASS__;
        }//ClassName

        public function Dump() {
            echo "TradeID \n<br>";var_dump($this->_trade);
            echo "Date \n<br>";var_dump($this->_date);
            echo "System \n<br>";var_dump($this->_system);
            echo "Data \n<br>";var_dump($this->data);
        } //dump

        //-------------------------------------------------------------------------------------
        protected function Prepare() {
            $this->_sqls();
            $this->data = $this->_db->handler->getAll($this->_sql_querys['forecast_list']);

            return $this->data;
        }//Prepare

        public function Build() {
            $this->Prepare();
            return $this->data;
        } //Build

        protected function _sqls() {
            $this->_sql_querys['forecast_list'] =
            "SELECT (f.CloseTime is null) AS flagActive,f.BeginPrice, f.BeginTime,f.EndPrice,f.EndTime, t.TradeID,t.Pair, f.Color, f.StopPrice, f.Side ".
                ( $this->flag_simple ? '':
                " ,COALESCE(f.CloseTime,lq.LastCloseTime) as CloseTime,   ".
                " COALESCE(f.ClosePrice,lq.LastClosePrice) as ClosePrice,   ".
                " round((1 - 2 * f.Side) * (COALESCE(f.ClosePrice, lq.LastClosePrice) - f.BeginPrice) / t.PipSize) as Pip "
                ) .

            "FROM vfa_forecast f ".
                   "LEFT OUTER JOIN fa_trades t ON (f.TradeID = t.TradeID) ".
                   ( $this->flag_simple ? '':
                   "LEFT OUTER JOIN " .
                    " ( " .
                     " SELECT " .
                          " ttq.TradeID, " .
                          " ttq.C as LastClosePrice, " .
                          " ttq.TimeStart as LastCloseTime " .
                     " FROM fa_quotes ttq " .
                         " RIGHT OUTER JOIN ( " .
                               " SELECT tq.TradeID, max(tq.TimeStart) as max_quote_time " .
                               " FROM fa_quotes tq " .
                               " GROUP BY tq.TradeID) qq " .
                               " ON (qq.max_quote_time=ttq.TimeStart and qq.TradeID=ttq.TradeID) " .
                    ") lq " .
                    "ON (f.TradeID = lq.TradeID) "
                   ).
            "WHERE f.TradeId=$this->_trade AND f.BeginTime=$this->_date ".( $this->_system ? " AND f.SystemID=$this->_system " : "" ).
            "ORDER BY f.EndTime";
        } //_sqls
    }    //class objForecatsBeginTimeShow
    //---------------------------------------------------------------------------------------------------
    class objExportServiceProcess {
            public $loging = true;
            public $type = 1;
            protected $Log = false;
            protected $trade = false;
            protected $start = false;
            protected $system = false;
            protected $data = false;

        public function __construct($aTrade, $aStart,  $aType=1, $aSystem=false) {
            $this->trade = intval($aTrade);
            $this->start = intval($aStart);
            $this->type = intval($aType);
            $this->system = $aSystem;
        } //constructor

        protected function StartLog() {
            $this->Log = new objTextLog('serviceexport');
        } //StartLog

        protected function GetData() {
            $ForecastData = new objForecatsBeginTimeShow($this->trade, $this->start, $this->system);
            $ForecastData->flag_simple = true;
            return $ForecastData->Build();
        } //GetData

        protected function GetBody($aLang, $aData, $aTemplateSource) {
          global $config;

            $Body = new objTemplate($aLang);
            $Body->Assign('forecast', $aData);
            $Body->Assign('countForecast', count($aData));

            return $Body->Fetch($config['smarty']['template_dir'] .'services/' . $aTemplateSource);
        } //getBody
        //--------------------------------------------------------------------------------------------
        protected function getAlert($html=true) {
            $newline = ($html ? "<hr>\n" : "\n");
            return " Trade=".var_export($this->trade, true) . $newline.
                                 " Start=" . var_export($this->start, true) . $newline.
                                 " Type=" . var_export($this->type, true) . $newline.
                                 " System=".var_export($this->system, true) . $newline.
                                 " Data=" . var_export($this->data, true);
        } //getAlert

        protected function viewAlert($subject='') {
            echo ($subject ? " $subject \n " : '') . $this->getAlert(false);
        } //viewAlert

        protected function SendAlert($subject='') {
          global $config;
            $AlertMailer = new objMailer();
            $AlertMailer->AddAddress($config['admin']['email']);
            $AlertMailer->isHTML( true );
            $AlertMailer->Subject = 'Error Alert: mailer service ' . $subject;
            $AlertMailer->Body = $this->getAlert();
            return $AlertMailer->Send();
        } //SendAlert

        protected  function Alert($subject='', $fSend=true, $fView=true) {
            if( $fSend ) $this->SendAlert($subject);
            if( $fView ) $this->viewAlert($subject);
        } //Alert
        //--------------------------------------------------------------------------------------------
        public function Send() {
          global $config;

            if( $this->loging ) $this->StartLog();

            $this->data = $this->GetData();
            $Clients = new objExportServiceClients($this->system);
            $clist = $Clients->GetList();

            if( empty($clist) ) return true;
            if( !$this->data ) {
                $this->Alert('empty data');
                throw new Exception("Service mailer error - empty data");
            } //alert: empty data

            $Mailer = new objMailer();
            $Mailer->SMTPKeepAlive=true;
            $Mailer->isHTML( false );
            foreach($clist as $item) {
                $Mailer->SetGlobalSettings();
                //---------------------------------------------------------------------------------------
                if( $item['mailer']['host'] ) {
                    $Mailer->Host = $item['mailer']['host'];
                    $Mailer->Port = $item['mailer']['port'];
                    $Mailer->Username = $item['mailer']['username'];  // SMTP username
                    $Mailer->Password = $item['mailer']['password']; // SMTP password
                } //if set different host

                if( $item['mailer']['emailfrom']) {
                    $Mailer->From = $item['mailer']['emailfrom'];
                } elseif( $item['mailer']['email'] ){
                    $Mailer->From = $item['mailer']['email'];
                }//if set different back adress
                //---------------------------------------------------------------------------------------
                $Mailer->Subject = $item['subject' . $this->type];
                $Mailer->AddAddress($item['email'], $item['name']);
                if( $config['mailer']['bcc'] ) $Mailer->AddBCC($config['mailer']['bcc']);
                //---------------------------------------------------------------------------------------
                $flag_body = true;
                $Mailer->Body = $this->GetBody('en', $this->data, $item['template' . $this->type]);
                if( !$Mailer->Body ) { //Alert: empty message
                    $this->Alert('empty body');
                    $flag_body = false;
                } //alert
                else $result = $Mailer->Send();

                if( $this->loging ) {
                    $log_data = $Mailer->Message;
                    $log_data['result'] = ($flag_body ? $Mailer->ErrorInfo : "empty body");
                    $this->Log->Add( new objMailerLogRecord($log_data) );
                    $this->Log->Flush();
                    unset($log_data);
                }//loging

                if( !$result || !$flag_body ) {
                    throw new Exception("There was an error sending the message. Error: ". $Mailer->ErrorInfo);
                }
                echo "\nMessage to ".$item['email']." was sent successfully";
                //---------------------------------------------------------------------------------------
                $Mailer->ClearAddresses();
            } //foreach
            $Mailer->SmtpClose();
            return true;
        } //Send

    } //class ExportServiceProcess
    //---------------------------------------------------------------------------------------------------
    class objResendMailer {
            public $loging = false;
            public $log_prefix = '';
            public $max_tries = 5;
            public $sleep_time = 10; //delay  in microseconds
            public $show = false;
            protected $_mailer_session = false;
            protected $MailRecord = false;
            protected $Log = false;

        public function __construct($aMailerSession=false) {
            $this->_mailer_session = $aMailerSession;
            $this->MailRecord = new objDBMailer_Mail();
        } //constructor

        protected function StartLog() {
            $this->Log = new objTextLog('mailer_resend_'.$this->log_prefix);
        } //StartLog

        protected function AddLog($aData) {
            $this->Log->Add( new objMailerLogRecord($aData) );
            $this->Log->Flush();
        } //AddLog

        public function Send() {
            $MailList = new objMailsNotSend();
            $MailList->MaxTries = $MailList->findMaxTries() + $this->max_tries;
            $MailList->MailerSession = $this->_mailer_session;

            if( $this->loging ) $this->StartLog();

            $t = 0;
            $mList = $MailList->GetAssocArr();
            if( $this->show ) echo "<pre>";
            $arrCaches = array();
            while( $mList && $t<$this->max_tries ) {
                if( $this->show ) echo "\n\n send tries: $t \n";
                foreach( $mList as $itemArr) {
                    if( $this->show ) echo $itemArr['MailID']." ";
                    $this->MailRecord->Load($itemArr['MailID']);
                    $result = $this->MailRecord->Send();
                    if( $this->MailRecord->cache && !in_array($this->MailRecord->cache, $arrCaches) )
                        $arrCaches[] = $this->MailRecord->cache;
                    if( $this->loging ) $this->AddLog($result);
                    if( $this->show ) echo "\n";
                } //for each mail
                if( $this->loging ) $this->Log->AddLine();
                usleep($this->sleep_time);

                $mList = $MailList->GetAssocArr(true);
                $t++;
            } //while list not empty and max tries doesn't reache

            //clear caches
            foreach($arrCaches as $cache) @unlink($cache);
            if( $this->show ) echo "</pre>";
        } //Send

        public function SendReport() {
            $MailList = new objMailsNotSend();
            $MailList->MaxTries = $MailList->findMaxTries() + 1;
            $MailList->MailerSession = $this->_mailer_session;
            if( !$MailList->isEmpty() ) {
                $mList = $MailList->GetAssocArr();
                $body = '';
                foreach( $mList as $itemArr) {
                    $this->MailRecord->Load($itemArr['MailID']);
                    $body = $this->MailRecord->forecastid .' '.
                            $this->MailRecord->userid .' '.
                            $this->MailRecord->mailid . ' <br>';
                } //for each mail

          global $config;

                $AlertMailer = new objMailer();
                $AlertMailer->AddAddress($config['admin']['email']);
                $AlertMailer->isHTML( true );
                $AlertMailer->Subject = 'Error Alert: list of not send mail ';
                $AlertMailer->Body = $body;
                $AlertMailer->Send();
            } //if not empty list
        } // SendReport

    } //class ResendMailer
//-------------------------------------------------------------------------------------------------------
?>
